/*-
 * Copyright (c) 2009-2010 David Forsythe.
 * See LICENSE file for license details.
 */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <err.h>
#include <sys/param.h>
#include <fetch.h>
#include <fcntl.h>
#include <libgen.h>

#include "internal.h"
#include "freebsd_repository_ftp.h"

#define PKG_EXTENSION ".tbz"
#define URLBUF_LEN              MAXHOSTNAMELEN + PATH_MAX

/*
 * The FreeBSD FTP repository isn't terribly complex.  Simply pass in the name
 * of a package and it will resolve it's location on a given server and retrieve
 * a file stream for the client.
 */

static int _pkg_repository_ftp_open(struct pkg_repository *, const char *,
        u_int);
static int _pkg_repository_ftp_close(struct pkg_repository *);
static FILE *_pkg_repository_ftp_fetch_pkg(struct pkg_repository *, 
        const char *, char **, size_t *, u_int);

struct _freebsd_ftp {
        /* Seems long enough... */
        char    base[MAXHOSTNAMELEN];
        /* Book keeping. */
        int     flags;
};

static struct pkg_repository_vtable _vt = {
        .open = _pkg_repository_ftp_open,
        .close = _pkg_repository_ftp_close,
        .fetch_pkg = _pkg_repository_ftp_fetch_pkg
};

struct pkg_repository_vtable *
pkg_repository_ftp_vtable(void)
{
        return (&_vt);
}

void
pkg_repository_ftp_init(struct pkg_repository *rp)
{
        _pkg_repository_set_vtable(rp, &_vt);
}

static int
_pkg_repository_ftp_open(struct pkg_repository *rp, const char *base, 
        u_int flags)
{
        struct _freebsd_ftp *ftp;
        struct url_stat st;
        (void)st;

        /* Allocate and initialize. */
        ftp = calloc(1, sizeof(*ftp));
        if (ftp == NULL) {
                return (PKG_NOT_OK);
        }
        strcpy(ftp->base, "");
        /* We need the ftp:// prefix for a valid url. */
        if (strncmp(base, "ftp://", 6) != 0) {
                strcat(ftp->base, "ftp://");
        }
        strcat(ftp->base, base);
        ftp->flags = flags;
        
        /* Check to make sure the repository actually exists. */
        if (fetchStatURL(ftp->base, &st, NULL) < 0) {
                free(ftp);
                return (PKG_NOT_OK);
        }

        /* Set the __internal pointer. */
        rp->internal = ftp;

        return (PKG_OK);
}

static int
_pkg_repository_ftp_close(struct pkg_repository *rp)
{
        struct _freebsd_ftp *ftp;

        ftp = rp->internal;
        free(ftp);
        return (PKG_OK);
}

static FILE *
_pkg_repository_ftp_fetch_pkg(struct pkg_repository *rp, 
        const char *name, char **fname, size_t *size, u_int flags)
{
        struct _freebsd_ftp *ftp;
        char url[MAXHOSTNAMELEN + PATH_MAX]; /* *shrug* */
        const char *base;
        struct url_stat st;
        FILE *fp;
        
        (void)flags;

        ftp = rp->internal;
        
        /* Build the entire URL for the fetch. */
        strcpy(url, ftp->base);
        strcat(url, "/");
        strcat(url, name);
        strcat(url, PKG_EXTENSION);
        
        base = basename(url);

        printf("%s\n", url);
        
        fp = fetchXGetURL(url, &st, NULL);
        if (fp == NULL) {
                /* XXX: I should really set up an error system in the library. 
                 */
                warnx("freebsd_ftp fetch failed -> %s", fetchLastErrString);
                return (NULL);
        }

        base = basename(url);
        *fname = strdup(base);

        /* Optional. */
        if (size != NULL) {
                *size = st.size;
        }
        
        return (fp);
}
